
/**
 *tagfolder
 *Licensed under LGPL
 *http://code.google.com/p/tagfolder
 *chuanshenglu@gmail.com
 *xrjieyee@gmail.com
 *
 */

#ifndef __TF_SERVER_BUFFER_H__
#define __TF_SERVER_BUFFER_H__

#include <string>
#include <map>
#include <set>
#include <fstream>

//============================================
//Abstract class to do server buffering ;
//============================================
/**
 *Abstract interface to all buffers;
 */
template< typename IDType, typename DataType >
class TFBuffer
{
    public:
        TFBuffer ( std::string& dbfile ) {}
        TFBuffer ( TFBuffer & ) {}
        virtual ~TFBuffer ( ) = 0;
        virtual void ShrinkBuffer ( ) = 0;
        virtual DataType GetById ( IDType id) = 0;
        virtual bool RemoveById ( IDType id ) = 0;
        virtual bool Add( DataType& obj ) = 0;
        virtual bool GetNextId() = 0;
        virtual long Size() = 0;
};
/**
 *TFServerBuffer:
 *
 *
 */
template < typename IDType, typename DataType >
class TFServerBuffer
//        :public TFBuffer<IDType, DataType>
{
    public:
        /**
         *Construct a TFServerBuffer object from a file;
         *the only construction approach;
         */
        TFServerBuffer ( std::string& dbfile ) 
            :idcount(0),
            opcount(0),
            dbfilename(dbfile)
    {
        LoadFromFile();
    }
        /**
         *Explicitly declare that do not copy construct!!!!
         */
        TFServerBuffer ( TFServerBuffer & ) { } 
        /**
         *Destructor
         */
        virtual ~TFServerBuffer ( )
        {
            WriteBack();
        }
        /**
         *Shrink buffer to proper size to ease memory burden;
         */
        virtual void ShrinkBuffer ( )
        {
        }
        /**
         *Get object from the buffer with id;
         */
        virtual DataType GetById ( IDType id)
        {
            DataType ret;
            //std::map<IDType, DataType>::iterator itr = Buffer.find(id);
            //if( itr != Buffer.end() )
            //{
                //return itr->second;
            //}
            return ret;
        }
        /**
         *Remove object by id;
         */
        virtual bool RemoveById ( IDType id )
        {
            //std::map<IDType, DataType>::iterator itr = Buffer.find(id);
            //if( itr != Buffer.end() )
            //{
                //Buffer.erase( itr );
                //return true;
            //}
            //idcount++;
            //opcount++;
            return false;
        }
        /**
         *Add object to the buffer;
         */
        virtual bool Add( DataType& obj )
        {
            Buffer.insert( std::pair<IDType, DataType>( GetNextId(), obj));
            return true;
        }
        /**
         *Get next unused id;
         */
        virtual bool GetNextId()
        {
            return ++idcount;
        }
        /**
         *How many objects was stored in this buffer;
         */
        virtual long Size()
        {
            return Buffer.size();
        }
    protected:
        /**
         *Write data back to file;
         */
        virtual bool WriteBack( )
        {
            if( dbfilename == "" )
            {
                return false;
            }
            //std::ofstream tfout;
            //tfout.open( dbfilename.c_str(),
                    //std::ofstream::binary | std::ofstream::out );
            //for(std::map<IDType, DataType>::iterator itr = Buffer.begin();
                    //itr != Buffer.end();
                    //itr++ )
            //{
                //tfout <<itr->first <<itr->second <<std::endl;
            //}
            //tfout.close();
            return true;
        }
        /**
         *Load data from file to memory;
         */
        virtual bool LoadFromFile( )
        {
            if( dbfilename == "" )
            {
                return false;
            }
            Buffer.clear();
            std::ifstream tfin;
            tfin.open( dbfilename.c_str(),
                    std::ifstream::binary | std::ifstream::in );
            while( tfin.good() )
            {
                DataType data;
                IDType id;
                tfin >> id;
                tfin >> data;
                if( idcount < id)
                {
                    idcount = id;
                } 
                Buffer.insert( std::pair<IDType, DataType>( id, data));
            }
            tfin.close();
            return true;
        }
    protected:
        std::string dbfilename;
        std::map<IDType, DataType> Buffer;
        IDType idcount;
        long opcount;
};
/*
//==============================================
//Buffer to hold strings 
//==============================================
class TFStringBuffer
//: public TFServerBuffer < long, std::string >
{
public:
TFStringBuffer( std::string& );
virtual ~TFStringBuffer ( );
public:
virtual void ShrinkBuffer ( );
virtual long Size ( );
virtual std::string GetById ( long );
virtual std::string GetByIndex ( long );
virtual bool RemoveById ( long );
virtual bool RemoveByIndex ( long );
virtual bool Add ( std::string& );
virtual bool FindId( long id )
{
return ( Buffer.find(id) != Buffer.end() );
}
virtual long GetNextId()
{
return ++IdCount;
}
virtual long GetStringId( std::string& );
protected:
virtual bool WriteBack();
protected:
std::map< long , std::string > Buffer;
std::string dbfile;
private:
unsigned long OpCount;
unsigned long IdCount;
};
*/
//define phantom types to be convineont;
typedef TFServerBuffer<long,std::string>  TFStringBuffer;
typedef TFServerBuffer<long,std::string>  TFTagBuffer;
typedef TFServerBuffer<long,std::string>  TFFileBuffer;
typedef TFServerBuffer<long,long>         TFLinkBuffer;


//================================================
//
//================================================
//singleton
class TFBufferManager
{
    public:
        virtual ~TFBufferManager();
        //virtual TFBuffer& GetBuffer(const char*);
        virtual TFStringBuffer& GetStringBuffer(const char* str)
        {
            std::string s(str);
            return GetStringBuffer(s);
        }
        virtual TFLinkBuffer& GetLinkBuffer(const char* str)
        {
            std::string s(str);
            return GetLinkBuffer(s);
        }
        virtual TFStringBuffer& GetStringBuffer(std::string&);
        virtual TFLinkBuffer& GetLinkBuffer(std::string&);
        static TFBufferManager& GetInstance();
    private:
        static TFBufferManager* instance;
        TFBufferManager();
        std::map<std::string,TFStringBuffer*> StringBuffers;
        std::map<std::string,TFLinkBuffer*> LinkBuffers;
    private:
        std::set<std::string> LegalBufferNames;
};

#endif
